#include "demuxthread.h"

DemuxThread::DemuxThread(AVPacketQueue *audio_queue, AVPacketQueue *video_queue)
    : audio_queue(audio_queue), video_queue(video_queue)
{

}

DemuxThread::~DemuxThread()
{
    if(thread_) {
        Stop();
    }
}

int DemuxThread::Init(const char *url)
{
    url_ = url;

    int ret = 0;

    ifmt_ctx_ = avformat_alloc_context();

    ret = avformat_open_input(&ifmt_ctx_, url, NULL, NULL);
    if(ret != 0) {
        av_strerror(ret, err2str, sizeof(err2str));
        qDebug() <<" avformat_open_input err : "<< err2str;
    }

    ret = avformat_find_stream_info(ifmt_ctx_, NULL);
    if(ret != 0) {
        av_strerror(ret, err2str, sizeof(err2str));
        qDebug() <<" avformat_find_stream_info err : "<< err2str;
    }

    av_dump_format(ifmt_ctx_, NULL, url, NULL);

    audio_index_ = av_find_best_stream(ifmt_ctx_, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
    video_index_ = av_find_best_stream(ifmt_ctx_, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    qDebug() <<" av_find_best_stream audio_index_:"<< audio_index_ << " video_index_:" << video_index_;
    if(audio_index_ < 0 || video_index_ < 0) {
        qDebug() <<" av_find_best_stream err : ";
    }

    return 0;
}

int DemuxThread::Start()
{
    thread_ = new std::thread(&DemuxThread::Run, this);
    if(!thread_) {
        qDebug() <<" new std::thread(&DemuxThread::Run, this) err : ";
        return -1;
    }
    return 0;
}

int DemuxThread::Stop()
{
    Thread::Stop();
    avformat_close_input(&ifmt_ctx_);

    return 0;
}

AVCodecParameters *DemuxThread::AudioCodecParameters()
{
    if(audio_index_ != -1) {
        return ifmt_ctx_->streams[audio_index_]->codecpar;
    }
    return nullptr;
}

AVCodecParameters *DemuxThread::VideoCodecParameters()
{
    if(video_index_ != -1) {
        return ifmt_ctx_->streams[video_index_]->codecpar;
    }
    return nullptr;
}

AVRational DemuxThread::AudioStreamTimebase()
{
    if(audio_index_ != -1) {
        return ifmt_ctx_->streams[audio_index_]->time_base;
    }
    return AVRational{0, 0};
}

AVRational DemuxThread::VideoStreamTimebase()
{
    if(video_index_ != -1) {
        return ifmt_ctx_->streams[video_index_]->time_base;
    }
    return AVRational{0, 0};
}

void DemuxThread::Run()
{
    int ret = 0;
    AVPacket pkt;

    while (abort_ != 1) {
        if(audio_queue->Size() > 100 || video_queue->Size() > 100) {
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
            continue;
        }


        ret = av_read_frame(ifmt_ctx_, &pkt);
        if(ret < 0) {
            av_strerror(ret, err2str, sizeof(err2str));
            qDebug() <<" av_read_frame err : "<< err2str;
            break;
        }
        if(pkt.stream_index == audio_index_) {
//            qDebug() <<" audio packet audio_queue size: " << audio_queue->Size();
            audio_queue->Push(&pkt);
//            av_packet_unref(&pkt);
        }else if(pkt.stream_index == video_index_) {
            qDebug() <<" video packet video_queue size: " << video_queue->Size();
            video_queue->Push(&pkt);
        }
        av_packet_unref(&pkt);
    }
}
